package cn.zhxu.pack;

public class ColorHSB {

    private float h;  // 色相
    private float s;  // 饱和度（0最灰白，1最色彩）
    private float b;  // 亮度(0最暗，1最亮)

    public ColorHSB() {
    }

    public ColorHSB(float h, float s, float b) {
        assert s >= 0 && s <= 1;
        assert b >= 0 && b <= 1;
        this.h = normalizeH(h);
        this.s = s;
        this.b = b;
    }

    /**
     * 色相反转
     */
    public ColorHSB reverse() {
        return rotate(180);
    }

    /**
     * 色相旋转
     */
    public ColorHSB rotate(float rh) {
        return new ColorHSB(normalizeH(h + rh), s, b);
    }

    /**
     * 亮度衰减
     */
    public ColorHSB darken(float rate) {
        assert rate >= 0 && rate <= 1;
        return new ColorHSB(h, s, b - b * rate);
    }

    /**
     * 亮度增强
     */
    public ColorHSB lighten(float rate) {
        assert rate >= 0 && rate <= 1;
        return new ColorHSB(h, s, b + (1 - b) * rate);
    }

    /**
     * 饱和度衰减
     */
    public ColorHSB weaken(float rate) {
        assert rate >= 0 && rate <= 1;
        return new ColorHSB(h, s - s * rate, b);
    }

    /**
     * 饱和度增强
     */
    public ColorHSB strengthen(float rate) {
        assert rate >= 0 && rate <= 1;
        return new ColorHSB(h, s + (1 - s) * rate, b);
    }

    public ColorRGB toRGB() {
        float v = b;
        float r = 0, g = 0, b = 0;
        int i = (int) ((h / 60) % 6);
        float f = (h / 60) - i;
        float p = v * (1 - s);
        float q = v * (1 - f * s);
        float t = v * (1 - (1 - f) * s);
        switch (i) {
            case 0:
                r = v;
                g = t;
                b = p;
                break;
            case 1:
                r = q;
                g = v;
                b = p;
                break;
            case 2:
                r = p;
                g = v;
                b = t;
                break;
            case 3:
                r = p;
                g = q;
                b = v;
                break;
            case 4:
                r = t;
                g = p;
                b = v;
                break;
            case 5:
                r = v;
                g = p;
                b = q;
                break;
            default:
                break;
        }
        return new ColorRGB((int) (r * 255.0), (int) (g * 255.0), (int) (b * 255.0));
    }

    @Override
    public String toString() {
        return toRGB().toString();
    }

    private float normalizeH(float h) {
        while (h >= 360) {
            h -= 360;
        }
        while (h < 0) {
            h += 360;
        }
        return h;
    }

    public float getH() {
        return h;
    }

    public void setH(float h) {
        this.h = normalizeH(h);
    }

    public float getS() {
        assert s >= 0 && s <= 1;
        return s;
    }

    public void setS(float s) {
        this.s = s;
    }

    public float getB() {
        return b;
    }

    public void setB(float b) {
        assert b >= 0 && b <= 1;
        this.b = b;
    }

}
